package edu.udo.sopra10.chaturaji.util;

import java.util.Collection;

/**
 * Assists in throwing exceptions, for example when verifying parameters.
 * 
 * @author Simon Dierl
 */
public final class ExceptionUtil {
	/**
	 * Verify that the parameter is not {@code null}.
	 * 
	 * @param <T>
	 *            the type of the parameter.
	 * @param obj
	 *            the object to test for being {@code == null}.
	 * @param name
	 *            the name of the parameter, used to write the exception.
	 * @return the original object, if it was not {@code null}.
	 * @throws NullPointerException
	 *             if the object was {@code null}.
	 */
	public static <T> T assertNotNull(T obj, String name)
			throws NullPointerException {
		if (obj == null) {
			throw new NullPointerException(new StringBuilder(name).append(
					" must be non-null").toString());
		}
		return obj;
	}

	/**
	 * Verify that the parameter is in a given range.
	 * 
	 * @param obj
	 *            the number to test for being in the range.
	 * @param min
	 *            the lowest allowable value for {@code obj}.
	 * @param max
	 *            the highest allowable value for {@code obj}.
	 * @param name
	 *            the name of the parameter, used to write the exception.
	 * @return the original number, if it was in {@code [min, max]}.
	 * @throws IllegalArgumentException
	 *             if the number was not in {@code [min, max]}.
	 */
	public static byte assertInRange(byte obj, byte min, byte max, String name)
			throws IllegalArgumentException {
		if (obj < min || obj > max) {
			throw new IllegalArgumentException(new StringBuilder(name)
					.append(" must be in [").append(min).append(", ")
					.append(max).append("], was ").append(obj).toString());
		}
		return obj;
	}

	/**
	 * Verify that the parameter is in a given range.
	 * 
	 * @param obj
	 *            the number to test for being in the range.
	 * @param min
	 *            the lowest allowable value for {@code obj}.
	 * @param max
	 *            the highest allowable value for {@code obj}.
	 * @param name
	 *            the name of the parameter, used to write the exception.
	 * @return the original number, if it was in {@code [min, max]}.
	 * @throws IllegalArgumentException
	 *             if the number was not in {@code [min, max]}.
	 */
	public static int assertInRange(int obj, int min, int max, String name)
			throws IllegalArgumentException {
		if (obj < min || obj > max) {
			throw new IllegalArgumentException(new StringBuilder(name)
					.append(" must be in [").append(min).append(", ")
					.append(max).append("], was ").append(obj).toString());
		}
		return obj;
	}

	/**
	 * Verify that the parameter is in a given range.
	 * 
	 * @param obj
	 *            the number to test for being in the range.
	 * @param min
	 *            the lowest allowable value for {@code obj}.
	 * @param max
	 *            the highest allowable value for {@code obj}.
	 * @param name
	 *            the name of the parameter, used to write the exception.
	 * @return the original number, if it was in {@code [min, max]}.
	 * @throws IllegalArgumentException
	 *             if the number was not in {@code [min, max]}.
	 */
	public static long assertInRange(long obj, long min, long max, String name)
			throws IllegalArgumentException {
		if (obj < min || obj > max) {
			throw new IllegalArgumentException(new StringBuilder(name)
					.append(" must be in [").append(min).append(", ")
					.append(max).append("], was ").append(obj).toString());
		}
		return obj;
	}

	/**
	 * Verify that the parameter does not {@link Collection#contains(Object)}
	 * {@code null}.
	 * 
	 * @param <T>
	 *            the type of the parameter.
	 * @param obj
	 *            the object to test for containing {@code null}, must not be
	 *            {@code null}.
	 * @param name
	 *            the name of the parameter, used to write the exception.
	 * @return the original object, if it did not contain {@code null}.
	 * @throws NullPointerException
	 *             if the object contained {@code null}.
	 */
	public static <T extends Collection<?>> T assertNotContainsNull(T obj,
			String name) throws NullPointerException {
		if (obj.contains(null)) {
			throw new NullPointerException(new StringBuilder(name).append(
					" must not contain null").toString());
		}
		return obj;
	}

	/**
	 * Verify that the parameter is not {@code null} and does not
	 * {@link Collection#contains(Object)} {@code null}.
	 * 
	 * @param <T>
	 *            the type of the parameter.
	 * @param obj
	 *            the object to test for being or containing {@code null}.
	 * @param name
	 *            the name of the parameter, used to write the exception.
	 * @return the original object, if it was not and did not contain
	 *         {@code null}.
	 * @throws NullPointerException
	 *             if the object was or contained {@code null}.
	 */
	public static <T extends Collection<?>> T assertNotNullOrContainsNull(
			T obj, String name) throws NullPointerException {
		return assertNotContainsNull(assertNotNull(obj, name), name);
	}

}
